﻿/*
 * Author: Duncan Jenkins
 * 
 * Growing Selection Blob Detection (Very stack sensitive due to recursion)
 * */

using System;
using System.Drawing;

namespace LibraryCS {
    public class RecursiveGrowingSelection : VisionAlgorithm {
        private VImage source;
        private int[] labeledPixels;
        private int blobCount;

        public RecursiveGrowingSelection(String name) : base(name) { }

        public override Bitmap DoAlgorithm(Bitmap sourceImage) {
            DetectBlobs(sourceImage);
            VImage output = new VImage(source.Width, source.Height);

            // Return a colored labeled image
            int colors = 256 * 256 * 256;

            //Set a standard incrementation value
            int increment = 15;

            if (blobCount != 0) {
                // Catch divide by zero
                increment = colors / blobCount;
            }

            for (int i = 0; i < labeledPixels.Length; i++) {
                int x = i % output.Width;
                int y = i / output.Width;

                // There's a LOT of blobs
                output.SetSinglePixel(x, y, increment * labeledPixels[i]);
            }

            output.ApplyPixelChanges();

            return output.localImage;
        }

        public int[] DetectBlobs(Bitmap sourceImage) {
            // Source Image must be binary!
            source = new VImage(sourceImage);
            labeledPixels = new int[source.Width * source.Height];
            int label = 0;

            // Iterate through the image, building blobs (We avoid the edges)
            for (int y = 0; y < source.Height; y++) {
                for (int x = 0; x < source.Width; x++) {
                    int pixel = y * source.Width + x;
                    if (source.GrayPixels[pixel] > 0 && labeledPixels[pixel] < 1) {
                        // Detected foreground pixel
                        growBlob(x, y, ++label);
                    }
                }
            }

            blobCount = label;

            return labeledPixels;
        }

        private void growBlob(int x, int y, int label) {
            // Iterate through all surrounding pixels
            for (int neighborY = -1; neighborY < 2; neighborY++) {
                for (int neighborX = -1; neighborX < 2; neighborX++) {
                    // Check if we are at the edges
                    if (x + neighborX < 0 || x + neighborX > source.Width) {
                        continue;
                    } else if (y + neighborY < 0 || y + neighborY > source.Height) {
                        continue;
                    }

                    // Calculate pixel index
                    int pixel = (y + neighborY) * source.Width + (x + neighborX);

                    // Check if this label has already been set, and if so, skip this pixel
                    if (labeledPixels[pixel] > 0) {
                        continue;
                    }

                    // If the neigboring pixel is a foreground pixel, assign the label to it
                    if (source.GrayPixels[pixel] > 0) {
                        // Label the pixel
                        labeledPixels[pixel] = label;
                        // Check the new pixel for surrounding pixels
                        growBlob((x + neighborX), (y + neighborY), label);
                    }
                }
            }
        }
    }
}
